class Car {
  // 字段
  engine: string; // 相当于constructor 里的 this.engine

  // 构造函数
  constructor(engine: string) {
    this.engine = engine;
  }

  // 方法
  disp(): string {
    return "发动机为 :   " + this.engine;
  }
}

var car = new Car("Engine 1");
console.log(car, car.disp());

/**
 * 类的继承
 */
class Shape {
  Area: number; //其实写不写都无所谓，主要是明朗

  constructor(a: number) {
    this.Area = a;
  }
}

class Circle extends Shape {
  disp(): string {
    return "圆的面积:  " + this.Area;
  }
}

var obj2 = new Circle(223);
console.log(obj2.disp());

//需要注意的是子类只能继承一个父类，TypeScript 不支持继承多个类，但支持多重继承，如下实例：
class Root {
  str: string;
}

class Child extends Root {}
class Leaf extends Child {} // 多重继承，继承了 Child 和 Root 类 this指向实例的特性仍不变

var obj3 = new Leaf();
obj3.str = "qwer";
console.log(obj3.str);

/**
 * 继承类的方法重写
 * 类继承后，子类可以对父类的方法重新定义，这个过程称之为方法的重写。
 * 其中 super 关键字是对父类的直接引用，该关键字可以引用父类的属性和方法。
 */
class PrinterClass {
  doPrint(): void {
    console.log("父类的 doPrint() 方法。");
  }
}

class StringPrinter extends PrinterClass {
  doPrint(): void {
    super.doPrint(); // 调用父类的函数
    console.log("子类的 doPrint()方法。");
  }
}

/**
 * static关键字
 * static 关键字用于定义类的数据成员（属性和方法）为静态的，静态成员可以直接通过类名调用。
 */
class StaticMem {
  static num: number;

  static disp(): void {
    console.log("num 值为 " + StaticMem.num);
  }
}
StaticMem.num = 12; // 初始化静态变量
StaticMem.disp(); // 调用静态方法

/**
 * instanceof 运算符
 * instanceof 运算符用于判断对象是否是指定的类型，如果是返回 true，否则返回 false。
 * instanceof 谁的实例？
 */
class Person {}
var obj6 = new Person();
var isPerson = obj6 instanceof Person;
console.log("obj 对象是 Person 类实例化来的吗？ " + isPerson);

/**
 *  访问控制修饰符
 *  TypeScript 中，可以使用访问控制符来保护对类、变量、方法和构造方法的访问。TypeScript 支持 3 种不同的访问权限。
 * 
    public（默认） : 公有，可以在任何地方被访问。
    protected : 受保护，可以被其自身以及其子类访问。
    private : 私有，只能被其定义所在的类访问。
 */
class Encapsulate {
  str1: string = "hello";
  private str2: string = "world";
  protected str3: string = "www";
  abc(): string {
    return this.str2 + this.str3;
  }
}

var obj7 = new Encapsulate();
console.log(obj7.str1); // 可访问
console.log(obj7.abc()); // 在类中访问

/**
 * 类和接口
 * 类可以实现接口，使用关键字 implements，并将 interest 字段作为类的属性使用。
 * 以下实例红 AgriLoan 类实现了 ILoan 接口：
 * 利用编辑器报错修复快速填充接口所需要的属性和方法
 */

interface ILoan {
  interest: number;
}
class AgriLoan implements ILoan {
  interest: number;
  rebate: number;
  constructor(interest: number, rebate: number) {
    this.interest = interest;
    this.rebate = rebate;
  }
}
var obj8 = new AgriLoan(10, 1);
console.log("利润为 : " + obj8.interest + "，抽成为 : " + obj8.rebate);
